home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / UUPC11QS.ARJ / UUXQT.C < prev   
C/C++ Source or Header  |  1991-12-07  |  47KB  |  1,332 lines

  1. /*
  2.       Program:    uuxqt.c              23 September 1991
  3.       Author:     Mitch Mitchell
  4.       Email:      mitch@harlie.lonestar.org
  5.  
  6.       This is a re-write of the (much cleaner) UUXQT.C originally
  7.       distributed with UUPC/Extended.  The modifications are
  8.       intended primarily to lay a foundation for support for the
  9.       more advanced features of UUX.
  10.  
  11.       Usage:      uuxqt -xDEBUG -sSYSTEM
  12.  
  13. */
  14.  
  15. /*--------------------------------------------------------------------*/
  16. /*                        System include files                        */
  17. /*--------------------------------------------------------------------*/
  18.  
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <ctype.h>
  23. #include <errno.h>
  24. #include <time.h>
  25. #include <fcntl.h>
  26. #include <process.h>
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #include <io.h>
  30.  
  31. /*--------------------------------------------------------------------*/
  32. /*                    UUPC/extended include files                     */
  33. /*--------------------------------------------------------------------*/
  34.  
  35. #include "lib.h"
  36. #include "hlib.h"
  37. #include "dater.h"
  38. #include "arpadate.h"
  39. #include "getopt.h"
  40. #include "getseq.h"
  41. #include "expath.h"
  42. #include "import.h"
  43. #include "readnext.h"
  44. #include "pushpop.h"
  45. #include "security.h"
  46. #include "hostable.h"
  47. #include "usertabl.h"
  48. #include "timestmp.h"
  49.  
  50. #define BETA_TEST
  51.  
  52. currentfile();
  53.  
  54. /*--------------------------------------------------------------------*/
  55. /*                      Execution flag defines                        */
  56. /*--------------------------------------------------------------------*/
  57.  
  58. typedef enum {
  59.         X_OUTPUT,     /* 'O' return output to "outnode"       */
  60.         X_FAILED,     /* 'Z' send status if command failed    */
  61.         X_SUCCESS,    /* 'n' send status if command succeeded */
  62.         X_INPUT,      /* 'B' return command input on error    */
  63.         X_USEEXEC,    /* 'E' process command using exec(2)    */
  64.         X_STATFIL,    /* 'M' return status to file on remote  */
  65.  
  66.         S_CORRUPT,
  67.         S_EMPTY,
  68.         S_NOREAD,
  69.         S_NOWRITE,
  70.         S_STDIN,
  71.  
  72.         E_NORMAL,
  73.         E_NOACC,
  74.         E_SIGNAL,
  75.         E_STATUS,
  76.         E_NOEXE,
  77.         E_FAILED,
  78.  
  79.         UU_LAST,
  80.  
  81.         } UU_FLAGS;
  82.  
  83. /*--------------------------------------------------------------------*/
  84. /*                          Global Variables                          */
  85. /*--------------------------------------------------------------------*/
  86.  
  87. static char *spool_fmt = SPOOLFMT;
  88. static char *dataf_fmt = DATAFFMT;
  89. static char *send_cmd  = "S %s %s %s -%s %s 0666 %s\n";
  90.  
  91. /*--------------------------------------------------------------------*/
  92. /*                        Internal prototypes                         */
  93. /*--------------------------------------------------------------------*/
  94.  
  95. static void usage( void );
  96.  
  97. static boolean copylocal(const char *from, const char *to);
  98.  
  99. static void cant(const char *file);
  100.  
  101. static boolean do_uuxqt( const char *system );
  102.  
  103. static void process( const char *fname, const char *remote );
  104.  
  105. char **create_environment(const char *logname,
  106.                           const char *requestor);
  107.  
  108. static void delete_environment( char **envp);
  109.  
  110. static boolean AppendData( const char *input, FILE* dataout);
  111.  
  112. static boolean do_copy( char *localfile,
  113.                        const char *rmtsystem,
  114.                        const char *remotefile,
  115.                        const char *requestor,
  116.                        const boolean success );
  117.  
  118. static void ReportResults(const int   status,
  119.                           const char *input,
  120.                                 char *output,
  121.                           const char *command,
  122.                           const char *job_id,
  123.                           const time_t jtime,
  124.                           const char *requestor,
  125.                           const char *outnode,
  126.                           const char *outname,
  127.                           const boolean xflag[],
  128.                           const char *statfil,
  129.                           const char *machine,
  130.                           const char *user);
  131.  
  132. static int shell(char *command,
  133.                  const char *inname,
  134.                  const char *outname,
  135.                  const char *remotename,
  136.                  boolean xflag[]);
  137.  
  138. static boolean MailStatus(char *tempfile,
  139.                           char *address,
  140.                           char *subject);
  141.  
  142. /*--------------------------------------------------------------------*/
  143. /*                         Limit memory usage                         */
  144. /*--------------------------------------------------------------------*/
  145.  
  146. #ifdef __TURBOC__
  147. unsigned _heaplen = 1024 * 25;
  148. #endif
  149.  
  150. /*--------------------------------------------------------------------*/
  151. /*    m a i n                                                         */
  152. /*                                                                    */
  153. /*    Main program                                                    */
  154. /*--------------------------------------------------------------------*/
  155.  
  156. void main( int argc, char **argv)
  157. {
  158.    int c;
  159.    extern char *optarg;
  160.    extern int   optind;
  161.    char *system = "all";
  162.  
  163. /*--------------------------------------------------------------------*/
  164. /*     Report our version number and date/time compiled               */
  165. /*--------------------------------------------------------------------*/
  166.  
  167.    debuglevel = 1;
  168.    banner( argv );
  169.  
  170. #if defined(__CORE__)
  171.    copywrong = strdup(copyright);
  172.    checkref(copywrong);
  173. #endif
  174.  
  175. /*--------------------------------------------------------------------*/
  176. /*                             Initialize                             */
  177. /*--------------------------------------------------------------------*/
  178.  
  179.    tzset();                      /* Set up time zone information  */
  180.  
  181.    if (!configure( B_UUIO ))
  182.       exit(1);   /* system configuration failed */
  183.  
  184. /*--------------------------------------------------------------------*/
  185. /*                  Switch to the spooling directory                  */
  186. /*--------------------------------------------------------------------*/
  187.  
  188.    PushDir( spooldir );
  189.    atexit( PopDir );
  190.  
  191. /*--------------------------------------------------------------------*/
  192. /*                     Initialize logging file                        */
  193. /*--------------------------------------------------------------------*/
  194.  
  195.    if ((logfile = FOPEN(XQTLOG, "a", TEXT)) == NULL)
  196.       cant(XQTLOG);
  197.  
  198.    logecho = TRUE;
  199.  
  200.    checkuser( mailbox  );     /* Force User Table to initialize      */
  201.    checkreal( mailserv );     /* Force Host Table to initialize      */
  202.  
  203.    if (!LoadSecurity())
  204.    {
  205.       printmsg(0,"Unable to initialize security, see previous message");
  206.       exit(2);
  207.    } /* if (!LoadSecurity()) */
  208.  
  209. /*--------------------------------------------------------------------*/
  210. /*        Process our arguments                                       */
  211. /*--------------------------------------------------------------------*/
  212.  
  213.    while ((c = getopt(argc, argv, "s:x:")) !=  EOF)
  214.       switch(c) {
  215.  
  216.       case 's':
  217.          system = strdup(optarg);
  218.          break;
  219.  
  220.       case 'x':
  221.          debuglevel = atoi( optarg );
  222.          break;
  223.  
  224.       case '?':
  225.          usage();
  226.          exit(1);
  227.          break;
  228.  
  229.       default:
  230.          printmsg(0, "uuxqt - invalid option -%c", c);
  231.          usage();
  232.          exit(2);
  233.          break;
  234.    }
  235.  
  236.    if (optind != argc) {
  237.       fputs("Extra parameter(s) at end.\n", stderr);
  238.       exit(2);
  239.    }
  240.  
  241. /*--------------------------------------------------------------------*/
  242. /*                Set up search path for our programs                 */
  243. /*--------------------------------------------------------------------*/
  244.  
  245.    if ( E_uuxqtpath != NULL )
  246.    {
  247.       char *p = malloc( 6 + strlen( E_uuxqtpath ));
  248.       checkref( p );
  249.              /*  ....+        5 characters plus \0 and length of path */
  250.       sprintf(p,"PATH=%s", E_uuxqtpath);
  251.  
  252.       if (putenv( p ))
  253.       {
  254.          printmsg(0,"Unable to set path \"%s\"", p);
  255.          panic();
  256.       } /* if (putenv( p )) */
  257.    } /* if ( E_uuxqtpath != NULL ) */
  258.  
  259. /*--------------------------------------------------------------------*/
  260. /*    Actually invoke the processing routine for the eXecute files    */
  261. /*--------------------------------------------------------------------*/
  262.  
  263.    do_uuxqt( system );
  264.    if( equal( system , "all" ) )
  265.        do_uuxqt( nodename );
  266.  
  267.    fclose(logfile);
  268.  
  269.    exit(0);
  270.  
  271. } /* main */
  272.  
  273. /*--------------------------------------------------------------------*/
  274. /*    d o _ u u x q t                                                 */
  275. /*                                                                    */
  276. /*    Processing incoming eXecute (X.*) files for a remote system     */
  277. /*--------------------------------------------------------------------*/
  278.  
  279. static boolean do_uuxqt( const char *system )
  280. {
  281.    struct HostTable *hostp;
  282.    static char uu_machine[] = UU_MACHINE "=";
  283.    char hostenv[sizeof uu_machine + 25 + 2];
  284.  
  285. /*--------------------------------------------------------------------*/
  286. /*                 Determine if we have a valid host                  */
  287. /*--------------------------------------------------------------------*/
  288.  
  289.    if( !equal( system , "all" ) ) {
  290.       if (equal( system , nodename ))
  291.           hostp = checkname( system );
  292.       else
  293.           hostp = checkreal( system );
  294.  
  295.       if (hostp  ==  BADHOST) {
  296.          printmsg(0, "Unknown host \"%s\".", system );
  297.          exit(1);
  298.       }
  299.  
  300.    } else
  301.         hostp = nexthost( TRUE , aliasof );
  302.  
  303. /*--------------------------------------------------------------------*/
  304. /*             Outer loop for processing different hosts              */
  305. /*--------------------------------------------------------------------*/
  306.  
  307.    while  (hostp != BADHOST)
  308.    {
  309.  
  310.       char fname[FILENAME_MAX];
  311.            /* Initialize security for this remote */
  312.  
  313.       if ( !equal(system, nodename) && (securep = GetSecurity( hostp )) == NULL ) {
  314.          printmsg(0,"No security defined for \"%s\", cannot process X.* files",
  315.                   hostp->hostname );
  316.       } else {
  317.  
  318. /*--------------------------------------------------------------------*/
  319. /*              Set up environment for the machine name               */
  320. /*--------------------------------------------------------------------*/
  321.  
  322.       sprintf(hostenv,"%s%.25s", uu_machine, hostp->hostname);
  323.       if (putenv( hostenv ))
  324.       {
  325.          printmsg(0,"Unable to set environment \"%s\"",hostenv);
  326.          panic();
  327.       }
  328.  
  329. /*--------------------------------------------------------------------*/
  330. /*           Inner loop for processing files from one host            */
  331. /*--------------------------------------------------------------------*/
  332.  
  333.          while (readnext(fname, hostp->hostname, "X", NULL) )
  334.             process( fname , hostp->hostname );
  335.  
  336.       } /* securep != NULL */
  337.  
  338. /*--------------------------------------------------------------------*/
  339. /*                        Restore environment                         */
  340. /*--------------------------------------------------------------------*/
  341.  
  342.       putenv( uu_machine );   /* Reset to empty string               */
  343.  
  344. /*--------------------------------------------------------------------*/
  345. /*    If processing all hosts, step to the next host in the queue     */
  346. /*--------------------------------------------------------------------*/
  347.  
  348.       if( equal(system,"all") )
  349.          hostp = nexthost( FALSE , aliasof );
  350.       else
  351.          hostp = BADHOST;
  352.  
  353.    } /*while nexthost*/
  354.  
  355.    return FALSE;
  356.  
  357. } /* do_uuxqt */
  358.  
  359. /*--------------------------------------------------------------------*/
  360. /*    p r o c e s s                                                   */
  361. /*                                                                    */
  362. /*    Process a single execute file                                   */
  363. /*--------------------------------------------------------------------*/
  364.  
  365. static void process( const char *fname, const char *remote )
  366. {
  367.    char *command = NULL,
  368.         *input = NULL,
  369.         *output = NULL,
  370.         *job_id = NULL,
  371.         *token = NULL,
  372.         line[BUFSIZ];
  373.    char hostfile[FILENAME_MAX];
  374.    boolean skip = FALSE;
  375.    boolean reject = FALSE;
  376.    FILE *fxqt;
  377.    int   status;
  378.  
  379.    char *outnode = NULL;
  380.    char *outname = NULL;
  381.    char *user = NULL;
  382.    char *requestor = NULL;
  383.    char *statfil = NULL;
  384.    char *machine = NULL;
  385.    char   **envp;
  386.  
  387.    boolean xflag[UU_LAST - 1] = { 0 };
  388.    time_t jtime = time(NULL);
  389.  
  390. /*--------------------------------------------------------------------*/
  391. /*                         Open the X.* file                          */
  392. /*--------------------------------------------------------------------*/
  393.  
  394.    if ( (fxqt = FOPEN(fname, "r", BINARY)) == NULL) {  /* inbound X.* file */
  395.       printerr(fname);
  396.       return;
  397.    }
  398.    else
  399.       printmsg(2, "processing %s", fname);
  400.  
  401. /*--------------------------------------------------------------------*/
  402. /*                  Begin loop to read the X.* file                   */
  403. /*--------------------------------------------------------------------*/
  404.  
  405.    while (!skip & (fgets(line, BUFSIZ, fxqt) != NULL)) {
  406.       char *cp;
  407.  
  408.       if ( (cp = strchr(line, '\n')) != NULL )
  409.          *cp = '\0';
  410.  
  411.       printmsg(8, "input read: %s", line);
  412.  
  413. /*--------------------------------------------------------------------*/
  414. /*            Process the input line according to its type            */
  415. /*--------------------------------------------------------------------*/
  416.  
  417.       switch (line[0])
  418.       {
  419.  
  420.       case '#':
  421.          break;
  422.  
  423. /*--------------------------------------------------------------------*/
  424. /*                  User which submitted the command                  */
  425. /*--------------------------------------------------------------------*/
  426.  
  427.       case 'U':
  428.          strtok(line," \t\n");      /* Trim off leading "U"       */
  429.                                     /* Get the user name          */
  430.          if ( (cp = strtok(NULL," \t\n")) == NULL ) {
  431.             printmsg(0,"No user on U line in file \"%s\"", fname );
  432.          } else {
  433.              user = strdup(cp);
  434.              checkref(user);
  435.          };
  436.                                     /* Get the system name        */
  437.          if ( (cp = strtok(NULL," \t\n")) == NULL)
  438.          {                          /* Did we get a string?       */
  439.             printmsg(2,"No node on U line in file \"%s\"", fname );
  440.             cp = (char *) remote;
  441.          } else if (!equal(cp,remote)) {
  442.             printmsg(2,"Node on U line in file \"%s\" doesn't match remote",
  443.                      fname );
  444.             cp = (char * ) remote;
  445.          };
  446.          machine = strdup(cp);
  447.          checkref(machine);
  448.          break;
  449.  
  450. /*--------------------------------------------------------------------*/
  451. /*                       Input file for command                       */
  452. /*--------------------------------------------------------------------*/
  453.  
  454.       case 'I':
  455.          input = strdup( &line[2] );                     /* ahd   */
  456.          checkref(input);
  457.          if (!equal(remote, nodename))
  458.             if (!(equaln(input,"D.",2) || ValidateFile( input, ALLOW_READ)))
  459.             {
  460.                 reject = TRUE;
  461.                 xflag[S_NOREAD] = TRUE;
  462.             }
  463.          break;
  464.  
  465. /*--------------------------------------------------------------------*/
  466. /*                      Output file for command                       */
  467. /*--------------------------------------------------------------------*/
  468.  
  469.       case 'O':
  470.          strtok(line," \t\n");      /* Trim off leading "U"       */
  471.                                     /* Get the user name          */
  472.          if ( (cp = strtok(NULL," \t\n")) != NULL )
  473.          {
  474.              output = strdup(cp);
  475.              checkref(output);
  476.              if ( (cp = strtok(NULL," \t\n")) != NULL)
  477.              {                /* Did we get a string?                */
  478.                    outnode = strdup(cp);
  479.                    checkref(outnode);
  480.                    checkreal(outnode);
  481.                    outname = output;
  482.                    output = mktempname(NULL, "OUT");
  483.                    xflag[X_OUTPUT] = TRUE;  /* return output to "outnode" */
  484.              }
  485.              else if (!equal(remote, nodename))
  486.              {
  487.                 if (!(equaln(output,"D.",2) || ValidateFile( output, ALLOW_WRITE)))
  488.                 {
  489.                     reject = TRUE;
  490.                     xflag[S_NOWRITE] = TRUE;
  491.                 } /* if */
  492.              } /* else if (!equal(remote, nodename)) */
  493.          } /* if ( (cp = strtok(NULL," \t\n")) != NULL ) */
  494.          break;
  495.  
  496. /*--------------------------------------------------------------------*/
  497. /*                         Command to execute                         */
  498. /*--------------------------------------------------------------------*/
  499.  
  500.       case 'C':
  501.          command = strdup( &line[2] );                   /* ahd   */
  502.          checkref(command);                              /* ahd   */
  503.          break;
  504.  
  505. /*--------------------------------------------------------------------*/
  506. /*                      Job Id for status reporting                   */
  507. /*--------------------------------------------------------------------*/
  508.  
  509.       case 'J':
  510.          strtok(line," \t\n");      /* Trim off leading "J"       */
  511.                                     /* Get the job id             */
  512.          if ( (cp = strtok(NULL," \t\n")) == NULL )
  513.          {
  514.             printmsg(0,"No job id on J line in file \"%s\"", fname );
  515.             reject = TRUE;
  516.          }
  517.          else {
  518.             job_id = strdup( cp );
  519.             checkref( job_id );
  520.          } /* else */
  521.          break;
  522.  
  523. /*--------------------------------------------------------------------*/
  524. /*                 Check that a required file exists                  */
  525. /*--------------------------------------------------------------------*/
  526.  
  527.       case 'F':
  528.          token = strtok(&line[1]," ");
  529.          importpath(hostfile, token, remote);
  530.  
  531.          if ( access( hostfile, 0 ))   /* Does the host file exist?  */
  532.          {                             /* No --> Skip the file       */
  533.             printmsg(0,"Missing file %s (%s) for %s, command skipped",
  534.                      token, hostfile, fname);
  535.             skip = TRUE;
  536.          }
  537.  
  538.          break;
  539.  
  540. /*--------------------------------------------------------------------*/
  541. /*             Requestor name (overrides user name, above)            */
  542. /*--------------------------------------------------------------------*/
  543.  
  544.       case 'R':
  545.          strtok(line," \t\n");      /* Trim off leading "R"       */
  546.                                     /* Get the user name          */
  547.          if ( (cp = strtok(NULL," \t\n")) == NULL )
  548.             printmsg(0,"No requestor on R line in file \"%s\"", fname );
  549.          else {
  550.             requestor = strdup(cp);
  551.             checkref(requestor);
  552.          }
  553.          break;
  554.  
  555. /*--------------------------------------------------------------------*/
  556. /*        Status file name to return info to on remote node           */
  557. /*--------------------------------------------------------------------*/
  558.  
  559.       case 'M':
  560.          strtok(line," \t\n");      /* Trim off leading "M"           */
  561.                                     /* Get the file name              */
  562.          if ( (cp = strtok(NULL," \t\n")) != NULL ) {
  563.             statfil = strdup(cp);
  564.             checkref(statfil);
  565.             xflag[X_STATFIL] = TRUE;     /* return status to remote file   */
  566.          } else {
  567.             printmsg(0,"No file name on M line in file \"%s\"", fname);
  568.          }
  569.          break;
  570.  
  571. /*--------------------------------------------------------------------*/
  572. /*                            Flag fields                             */
  573. /*--------------------------------------------------------------------*/
  574.  
  575.       case 'Z': xflag[X_FAILED] = TRUE;   /* send status if command failed */
  576.          break;
  577.  
  578.       case 'N': xflag[X_FAILED] = FALSE;  /* send NO status if command failed */
  579.          break;
  580.  
  581.       case 'n': xflag[X_SUCCESS] = TRUE;  /* send status if command succeeded */
  582.          break;
  583.  
  584.       case 'z': xflag[X_SUCCESS] = FALSE; /* NO status if command succeeded */
  585.          break;
  586.  
  587.       case 'B': xflag[X_INPUT] = TRUE;    /* return command input on error */
  588.          break;
  589.  
  590.       case 'e': xflag[X_USEEXEC] = FALSE; /* process command using sh(1) */
  591.          break;
  592.  
  593.       case 'E': xflag[X_USEEXEC] = TRUE;  /* process command using exec(2) */
  594.          break;
  595.  
  596. /*--------------------------------------------------------------------*/
  597. /*                    Quietly ignore unknown fields                   */
  598. /*--------------------------------------------------------------------*/
  599.  
  600.       default :
  601.          break;
  602.  
  603.       } /* switch */
  604.    } /* while (!skip & (fgets(line, BUFSIZ, fxqt) != NULL)) */
  605.  
  606.    if ( fxqt != NULL )
  607.       fclose(fxqt);
  608.  
  609.  
  610.    if ((command == NULL) && !skip)
  611.    {
  612.       printmsg(0,"No command supplied for X.* file %s, skipped", fname);
  613.       reject = TRUE;
  614.    }
  615.  
  616. /*--------------------------------------------------------------------*/
  617. /*           We have the data for this command; process it            */
  618. /*--------------------------------------------------------------------*/
  619.  
  620.    if ( ! (skip || reject ))
  621.    {
  622.       if ( user == NULL )
  623.       {
  624.          user = strdup("uucp");    /* User if none given         */
  625.          checkref(user);
  626.       }
  627.  
  628.       if (requestor == NULL)
  629.       {
  630.          requestor = strdup(user);
  631.          checkref(requestor);
  632.       }
  633.  
  634.       if (input == NULL)
  635.          input = strdup("nul");
  636.  
  637.       if (output == NULL)
  638.          output = mktempname(NULL, "OUT");
  639.  
  640.       printmsg(2, "xqt: %s", command);
  641.  
  642.       envp = create_environment("uucp", requestor);
  643.       status = shell(command, input, output, remote, xflag );
  644.       delete_environment(envp);
  645.  
  646.       ReportResults( status, input, output, command, job_id,
  647.                      jtime, requestor, outnode, outname, xflag,
  648.                      statfil, machine, user);
  649.  
  650. /*--------------------------------------------------------------------*/
  651. /*              If no serious problems, delete the input              */
  652. /*--------------------------------------------------------------------*/
  653.  
  654.       if ( status >= 0 )
  655.       {
  656.          unlink(fname);       /* Already a local file name            */
  657.  
  658.          if (equaln(input,"D.",2))
  659.          {
  660.              importpath(hostfile, input, remote);
  661.              unlink(hostfile);
  662.          }
  663.  
  664.          if (xflag[X_OUTPUT])
  665.          {
  666.              importpath(hostfile, output, remote);
  667.              unlink(hostfile);
  668.          }
  669.       }
  670.  
  671.    } else if (reject && !skip)
  672.         unlink(fname);       /* Already a local file name            */
  673.  
  674. /*--------------------------------------------------------------------*/
  675. /*              Free various temporary character strings              */
  676. /*--------------------------------------------------------------------*/
  677.  
  678.    if (command    != NULL) free(command);
  679.    if (input      != NULL) free(input);
  680.    if (job_id     != NULL) free(job_id);
  681.    if (machine    != NULL) free(machine);
  682.    if (outnode    != NULL) free(outnode);
  683.    if (output     != NULL) free(output);
  684.    if (requestor  != NULL) free(requestor);
  685.    if (statfil    != NULL) free(statfil);
  686.    if (user       != NULL) free(user);
  687.  
  688. } /* process */
  689.  
  690. /*--------------------------------------------------------------------*/
  691. /*    s h e l l                                                       */
  692. /*                                                                    */
  693. /*    Simulate a Unix command                                         */
  694. /*--------------------------------------------------------------------*/
  695.  
  696. static int shell(char *command,
  697.                  const char *inname,
  698.                  const char *outname,
  699.                  const char *remotename,
  700.                  boolean xflag[])
  701. {
  702.    char  *argv[50];
  703.    int    argc;
  704.    int    result = 0;
  705.    char   inlocal[FILENAME_MAX];
  706.    char   outlocal[FILENAME_MAX];
  707.  
  708.    if (!xflag[X_USEEXEC])
  709.       printmsg(2, "exec(2) not supported, executing using spawn");
  710.  
  711.    argc = getargs(command, argv);
  712.  
  713.    printmsg(2,"uux: command arg count = %d", argc);
  714.    if (debuglevel >= 2) {
  715.       char **argvp = argv;
  716.       int i = 0;
  717.       while (i < argc)
  718.          printmsg(2, "shell: argv[%d]=\"%s\"", i++, *argvp++);
  719.    }
  720.  
  721. /*--------------------------------------------------------------------*/
  722. /*    Verify we support the command, and get it's real name, if so    */
  723. /*--------------------------------------------------------------------*/
  724.  
  725.    if ( (!equal(remotename, nodename)) && (!ValidateCommand( argv[0] )) )
  726.    {
  727.       printmsg(0,"Command \"%s\" not allowed at this site", argv[0]);
  728.       xflag[E_NOEXE] = TRUE;
  729.       return 99;
  730.    }
  731.  
  732.    if (equal(argv[0], "rmail"))
  733.       argv[0] = E_rmail;
  734.    else if (equal(argv[0], "rnews"))
  735.       argv[0] = E_rnews;
  736.  
  737. /*--------------------------------------------------------------------*/
  738. /*                     Open files for processing                      */
  739. /*--------------------------------------------------------------------*/
  740.  
  741.    if (inname != NULL) {
  742.       importpath(inlocal, inname, remotename);
  743.       printmsg(2, "shell: opening %s for input", inlocal);
  744.       if (freopen(inlocal, "rb", stdin) == NULL) {
  745.          printmsg(0, "shell: couldn't open %s (%s), errno=%d.",
  746.             inname, inlocal, errno);
  747.          printerr(inlocal);
  748.          xflag[S_CORRUPT] = TRUE;
  749.          return -2;
  750.       }
  751.    }
  752.  
  753.    if (outname != NULL) {
  754.       importpath(outlocal, outname, remotename);
  755.       printmsg(2, "shell: opening %s for output", outlocal);
  756.       if (freopen(outlocal, "wt", stdout) == NULL) {
  757.          printmsg(0, "shell: couldn't open %s (%s), errno=%d.",
  758.             outname, outlocal, errno);
  759.          printerr(outlocal);
  760.          if ( inname != NULL)
  761.             freopen("con", "rt", stdin);
  762.          xflag[S_NOWRITE] = TRUE;
  763.          return -2;
  764.       }
  765.    }
  766.  
  767. /*--------------------------------------------------------------------*/
  768. /*               We support the command; execute it                   */
  769. /*--------------------------------------------------------------------*/
  770.  
  771.    argv[argc] = NULL;
  772.    fflush(logfile);
  773.  
  774.    if ((argv[0] == E_rmail) && ( inname != NULL )) /* Rmail w/input? */
  775.    {
  776.       int addr = 1;
  777.  
  778.       while (( addr < argc )  && (result != -1 ))
  779.       {
  780. #ifdef __TURBOC__
  781.          size_t rlen = 126;
  782.          char buf[128];
  783. #else
  784.          size_t rlen = (_osmode == DOS_MODE) ? 126 :  254;
  785.          char buf[255];
  786. #endif
  787.          rlen -= strlen( argv[0] );
  788.                               /* Compute space left on command line  */
  789.          *buf = '\0';         /* Terminate the buffer string         */
  790.  
  791. /*--------------------------------------------------------------------*/
  792. /*                   Copy addresses into the buffer                   */
  793. /*--------------------------------------------------------------------*/
  794.  
  795.          while (( addr < argc ) && (rlen >= strlen( argv[addr] )))
  796.          {
  797.             strcat( buf, argv[addr] );
  798.             rlen -= strlen( argv[addr++] ) + 1;
  799.             if (rlen > 0)     /* Room for another address?           */
  800.                strcat( buf, " ");   /* Yes --> Add space after addr  */
  801.          } /* while (( addr < argc ) && (rlen >= strlen( argv[addr] ) */
  802.  
  803.          if (*buf == '\0')    /* Did we process at least one addr?   */
  804.          {                    /* No --> Serious problem!             */
  805.             printmsg(0,"shell: address \"%s\" too long to process!",
  806.                   argv[addr] );
  807.             panic();
  808.          } /* if (*buf = '\0') */
  809.  
  810. /*--------------------------------------------------------------------*/
  811. /*               Execute one command line of addresses                */
  812. /*--------------------------------------------------------------------*/
  813.  
  814.          printmsg(2, "shell: %s %s", argv[0], buf );
  815.  
  816.          result = spawnlp( P_WAIT, argv[0], argv[0], buf , NULL);
  817.          xflag[result == 0 ? E_NORMAL : E_STATUS] = TRUE;
  818.  
  819.          if (freopen(inlocal, "rb", stdin) == NULL)
  820.          {
  821.             printmsg(0, "shell: couldn't reopen %s (%s), errno=%d.",
  822.                inname, inlocal, errno);
  823.             printerr(inlocal);
  824.             panic();
  825.          } /* if */
  826.  
  827.          if ( result > 0 )
  828.          {
  829.             printmsg(0,"shell: RMAIL command may have failed: %s",
  830.                      buf);
  831.             panic();
  832.          }
  833.       } /* while (( addr < argc )  && (result != -1 )) */
  834.  
  835.    } /* if ((argv[0] == E_rmail) && ( inname != NULL ))  */
  836.    else  {              /* No --> Invoke normally                 */
  837.       result = spawnvp( P_WAIT, argv[0], argv );
  838.       xflag[result == 0 ? E_NORMAL : E_STATUS] = TRUE;
  839.    } /* else */
  840.  
  841.    if (result == -1)       /* Did spawn fail?                     */
  842.       printerr(argv[0]);   /* Yes --> Report error                */
  843.  
  844. /*--------------------------------------------------------------------*/
  845. /*                  Re-open our standard i/o streams                  */
  846. /*--------------------------------------------------------------------*/
  847.  
  848.    fclose(stdout);
  849.    errno = 0;
  850.  
  851.    if ( outname != NULL )
  852.       freopen("con", "wt", stdout);
  853.  
  854.    errno = 0;
  855.  
  856.    if ( inname != NULL )
  857.    {
  858.       freopen("con", "rt", stdin);
  859.       if ( errno != 0 )
  860.       {
  861.          printerr("stdin");
  862.          panic();
  863.       }
  864.    } /* if ( inname != NULL ) */
  865.  
  866. /*--------------------------------------------------------------------*/
  867. /*                     Report results of command                      */
  868. /*--------------------------------------------------------------------*/
  869.  
  870.    printmsg( (result == 0 ) ? 8 : 1,"Result of spawn %s is ... %d",
  871.                                  argv[0], result);
  872.    fflush(logfile);
  873.  
  874.    return result;
  875.  
  876. } /*shell*/
  877.  
  878. /*--------------------------------------------------------------------*/
  879. /*    u s a g e                                                       */
  880. /*                                                                    */
  881. /*    Report how to run this program                                  */
  882. /*--------------------------------------------------------------------*/
  883.  
  884. static void usage( void )
  885. {
  886.    fputs("Usage:\tuuxqt\t[-xDEGUG] [-sSYSTEM]", stderr);
  887.    exit(1);
  888. } /* usage */
  889.  
  890. /*--------------------------------------------------------------------*/
  891. /*    c o p y l o c a l                                               */
  892. /*                                                                    */
  893. /*    Copy Local Files                                                */
  894. /*--------------------------------------------------------------------*/
  895.  
  896. static boolean copylocal(const char *from, const char *to)
  897. {
  898.       int  fd_from, fd_to;
  899.       int  nr;
  900.       int  nw = -1;
  901.       char buf[BUFSIZ];            /* faster if we alloc a big buffer */
  902.  
  903.       /* This would be even faster if we determined that both files
  904.          were on the same device, dos >= 3.0, and used the dos move
  905.          function */
  906.  
  907.       if ((fd_from = open(from, O_RDONLY | O_BINARY)) == -1)
  908.          return FALSE;        /* failed */
  909.  
  910.       /* what if the to is a directory? */
  911.       /* possible with local source & dest uucp */
  912.  
  913.       if ((fd_to = open(to, O_CREAT | O_BINARY | O_WRONLY, S_IWRITE | S_IREAD)) == -1) {
  914.          close(fd_from);
  915.          return FALSE;        /* failed */
  916.          /* NOTE - this assumes all the required directories exist!  */
  917.       }
  918.  
  919.       while  ((nr = read(fd_from, buf, sizeof buf)) > 0 &&
  920.          (nw = write(fd_to, buf, nr)) == nr)
  921.          ;
  922.  
  923.       close(fd_to);
  924.       close(fd_from);
  925.  
  926.       if (nr != 0 || nw == -1)
  927.          return FALSE;        /* failed in copy */
  928.       return TRUE;
  929. } /* copylocal */
  930.  
  931. /*--------------------------------------------------------------------*/
  932. /*    c r e a t e _ e n v i r o n m e n t                             */
  933. /*                                                                    */
  934. /*    Create the environment array for subprocesses                   */
  935. /*--------------------------------------------------------------------*/
  936.  
  937. char **create_environment(const char *logname,
  938.                           const char *requestor)
  939. {
  940.    char buffer[MAXADDR + 20];
  941.    int subscript = 0;
  942.    char **envp = (char **) malloc(sizeof(char *) * 3);
  943.  
  944.    checkref(envp);
  945.  
  946. /*--------------------------------------------------------------------*/
  947. /*              "Current" user id processing the request              */
  948. /*--------------------------------------------------------------------*/
  949.  
  950.    if ( logname != NULL )
  951.    {
  952.      sprintf(buffer,"%s=%s", LOGNAME, logname);
  953.      envp[subscript] = strdup(buffer);
  954.      checkref(envp[subscript++]);
  955.    }
  956.  
  957. /*--------------------------------------------------------------------*/
  958. /*               user id/nodename of original requestor               */
  959. /*--------------------------------------------------------------------*/
  960.  
  961.    if ( requestor != NULL )
  962.    {
  963.       sprintf(buffer,"%s=%s",UU_USER, requestor);
  964.       envp[subscript] =  strdup(buffer);
  965.       checkref(envp[subscript++]);
  966.    }
  967.  
  968.    envp[subscript] =  NULL;   /* Terminate the list                  */
  969.  
  970. /*--------------------------------------------------------------------*/
  971. /*               Now put the data into our environment                */
  972. /*--------------------------------------------------------------------*/
  973.  
  974.    while( subscript-- > 0)
  975.    {
  976.       if (putenv( envp[subscript] ))
  977.       {
  978.          printmsg(0,"Unable to set environment \"%s\"",envp[subscript]);
  979.          panic();
  980.       }
  981.    } /* while */
  982.  
  983.    return envp;
  984. } /* create_environment */
  985.  
  986. /*--------------------------------------------------------------------*/
  987. /*    d e l e t e  _ e n v i r o n m e n t                            */
  988. /*                                                                    */
  989. /*    Delete variables inserted by create_enviroment                  */
  990. /*                                                                    */
  991. /*    Our environment goes away when we are done executing we; just   */
  992. /*    clean up the environment because we are freeing the storage     */
  993. /*--------------------------------------------------------------------*/
  994.  
  995. static void delete_environment( char **envp )
  996. {
  997.    int subscript = 0;
  998.  
  999.    while ( envp[subscript] != NULL )
  1000.    {
  1001.       char *equal = strchr(envp[subscript]  , '=' );
  1002.       *++equal = '\0';        /* Terminate the string             */
  1003.       if (putenv( envp[subscript] ))
  1004.       {
  1005.          printmsg(0,"Unable to reset environment \"%s\"",envp[subscript]);
  1006.          panic();
  1007.       }
  1008.       free( envp[subscript++] );
  1009.    }
  1010.  
  1011.    free( envp );
  1012. } /* delete_environment */
  1013.  
  1014.  
  1015. /*--------------------------------------------------------------------*/
  1016. /*    d o _ c o p y                                                   */
  1017. /*                                                                    */
  1018. /*    Send a file to remote node via uucp                             */
  1019. /*--------------------------------------------------------------------*/
  1020.  
  1021. static boolean do_copy(char *localfile,
  1022.                        const char *rmtsystem,
  1023.                        const char *remotefile,
  1024.                        const char *requestor,
  1025.                        const boolean success )
  1026. {
  1027.       char    tmfile[FILENAME_MAX];  /* Unix style name for c file */
  1028.       char    idfile[FILENAME_MAX];  /* Unix style name for data file copy */
  1029.       char    work[FILENAME_MAX]; /* temp area for filename hacking */
  1030.       char    icfilename[FILENAME_MAX];  /* our hacked c file path */
  1031.       char    idfilename[FILENAME_MAX];  /* our hacked d file path */
  1032.  
  1033.       struct  stat    statbuf;
  1034.  
  1035.       long    int     sequence;
  1036.       static  char    subseq = 'A';
  1037.       char    *sequence_s;
  1038.       FILE        *cfile;
  1039.  
  1040.       sequence = getseq();
  1041.       sequence_s = JobNumber( sequence );
  1042.  
  1043.       sprintf(tmfile, spool_fmt, 'C', rmtsystem, 'Z', sequence_s);
  1044.       importpath(work, tmfile, rmtsystem);
  1045.       mkfilename(icfilename, spooldir, work);
  1046.  
  1047.       if (stat((char *) localfile, &statbuf) != 0)  {
  1048.           printerr( localfile );
  1049.           return FALSE;
  1050.       }
  1051.  
  1052.       sprintf(idfile , dataf_fmt, 'D', nodename, sequence_s, (char) subseq++);
  1053.       importpath(work, idfile, rmtsystem);
  1054.       mkfilename(idfilename, spooldir, work);
  1055.  
  1056.       if (!copylocal(localfile, idfilename))  {
  1057.          printmsg(0, "Copy \"%s\" to \"%s\" failed", localfile, idfilename);
  1058.          return FALSE;
  1059.       }
  1060.  
  1061.       if ((cfile = FOPEN(icfilename, "a", TEXT)) == NULL)  {
  1062.          printerr( icfilename );
  1063.          printf("cannot append to %s\n", icfilename);
  1064.          return FALSE;
  1065.       }
  1066.  
  1067.       fprintf(cfile, send_cmd, localfile, remotefile,
  1068.                "uucp" , success ? "n" : " ", idfile,
  1069.                 success ? requestor : " ");
  1070.  
  1071.       fclose(cfile);
  1072.  
  1073.       return TRUE;
  1074. } /* do_copy */
  1075.  
  1076.  
  1077. /*--------------------------------------------------------------------*/
  1078. /*    c a n t                                                         */
  1079. /*                                                                    */
  1080. /*    report that we cannot open a critical file                      */
  1081. /*--------------------------------------------------------------------*/
  1082.  
  1083. static void cant(const char *file)
  1084. {
  1085.    fprintf(stderr, "Can't open: \"%s\"\n", file);
  1086.    perror( file );
  1087.    panic();
  1088. } /*cant*/
  1089.  
  1090. /*--------------------------------------------------------------------*/
  1091. /*    R e p o r t R e s u l t s                                       */
  1092. /*                                                                    */
  1093. /*    report results of command execution as specified by flags in    */
  1094. /*    X.* file.                                                       */
  1095. /*--------------------------------------------------------------------*/
  1096.  
  1097. static void ReportResults(const int status,
  1098.                           const char *input,
  1099.                                 char *output,
  1100.                           const char *command,
  1101.                           const char *job_id,
  1102.                           const time_t jtime,
  1103.                           const char *requestor,
  1104.                           const char *outnode,
  1105.                           const char *outname,
  1106.                           const boolean xflag[],
  1107.                           const char *statfil,
  1108.                           const char *machine,
  1109.                           const char *user)
  1110. {
  1111.      char address[MAXADDR];
  1112.      char subject[80];
  1113.      FILE *mailtmp = NULL;
  1114.      char *tempmail = mktempname(NULL, "TMP");
  1115.  
  1116.  
  1117.      if (!(xflag[X_FAILED] | xflag[X_SUCCESS] |
  1118.            xflag[X_INPUT]  | xflag[X_STATFIL]))
  1119.      {  /* default actions */
  1120.          unlink(output);
  1121.          return;
  1122.      }
  1123.  
  1124.      if ((mailtmp = FOPEN(tempmail, "w+", BINARY)) == NULL) {
  1125.          printerr(tempmail);
  1126.          return;
  1127.      }
  1128.  
  1129.      fprintf(mailtmp,"remote execution");
  1130.      fprintf(mailtmp,"[uucp job %s (%s)]\n", job_id, dater(jtime, NULL) );
  1131.      fprintf(mailtmp,"%s\n", command);
  1132.  
  1133.      sprintf(subject, "[uucp job %s (%s)]", job_id, dater(jtime, NULL) );
  1134.  
  1135. #ifdef BETA_TEST
  1136.      strcpy(address,"postmaster");
  1137. #else
  1138.      if (equal(remotename, nodename))
  1139.          sprintf(address,"%s", requestor);
  1140.      else
  1141.          sprintf(address,"%s!%s", machine, requestor);
  1142. #endif
  1143.  
  1144.      if (xflag[E_NORMAL])
  1145.      {                        /* command succeded, process appropriate flags */
  1146.  
  1147.        fprintf(mailtmp,"exited normally\n");
  1148.  
  1149.        if (xflag[X_OUTPUT]) {
  1150.            if (outnode == NULL)
  1151.                copylocal(output, outname);
  1152.            else
  1153.                do_copy(output, outnode, outname, requestor, xflag[X_SUCCESS]);
  1154.        } else
  1155.            unlink(output);
  1156.  
  1157.        fclose(mailtmp);
  1158.  
  1159.        if (xflag[X_SUCCESS]) {
  1160.           if (xflag[X_STATFIL]) {
  1161.               if (outnode == NULL)
  1162.                   copylocal(tempmail, statfil);
  1163.               else
  1164.                   do_copy(tempmail, outnode, statfil, requestor, xflag[X_SUCCESS]);
  1165.           } else {
  1166.               MailStatus(tempmail, address, subject);
  1167.           }
  1168.        };
  1169.  
  1170.    } else {            /* command failed, process appropriate flags   */
  1171.      if (xflag[E_NOACC])
  1172.          fprintf(mailtmp,"file access denied to %s!%s", machine, user);
  1173.      else if (xflag[E_NOEXE])
  1174.         fprintf(mailtmp,"execution permission denied to %s!%s\n",
  1175.                 machine, requestor);
  1176.      else if (xflag[E_SIGNAL])
  1177.         fprintf(mailtmp,"terminated by signal\n");
  1178.      else if (xflag[E_STATUS])
  1179.         fprintf(mailtmp,"exited with status %d\n", status);
  1180.      else /* xflag->e & E_FAILED */
  1181.         fprintf(mailtmp,"failed completely\n");
  1182.  
  1183.  
  1184.      if (xflag[E_STATUS]) {
  1185.        if ((xflag[X_FAILED]) && !(xflag[X_INPUT])) {
  1186.            fprintf(mailtmp,"===== error output not available =====\n");
  1187.        } else if ((xflag[X_FAILED]) && (xflag[X_INPUT])) {
  1188.            fprintf(mailtmp,"===== stdin was ");
  1189.  
  1190.            if (xflag[S_CORRUPT])
  1191.                fprintf(mailtmp,"unreadable =====\n");
  1192.            else if (xflag[S_EMPTY])
  1193.                fprintf(mailtmp,"empty =====\n");
  1194.            else if (xflag[S_NOREAD])
  1195.                fprintf(mailtmp,"denied read permission =====\n");
  1196.            else {
  1197.                fprintf(mailtmp,"=====\n");
  1198.                AppendData( input, mailtmp);
  1199.            };
  1200.            unlink(input);
  1201.  
  1202.            fprintf(mailtmp,"===== stderr is unavailable =====\n");
  1203.        }
  1204.      }
  1205.  
  1206.      fclose(mailtmp);
  1207.  
  1208.      if (xflag[X_STATFIL]) {
  1209.          if (outnode == NULL)
  1210.              copylocal(tempmail, statfil);
  1211.          else
  1212.              do_copy(tempmail, outnode, statfil, requestor, xflag[X_SUCCESS]);
  1213.      } else {
  1214.          MailStatus(tempmail, address, subject);
  1215.      }
  1216.  
  1217.    }
  1218.  
  1219.    if (!xflag[X_OUTPUT])
  1220.        unlink(output);
  1221.  
  1222.    unlink(tempmail);
  1223.    return;
  1224. } /* ReportResults */
  1225.  
  1226. /*--------------------------------------------------------------------*/
  1227. /* A p p e n d D a t a                                                */
  1228. /*                                                                    */
  1229. /* Append data to output file                                         */
  1230. /*--------------------------------------------------------------------*/
  1231.  
  1232. static boolean AppendData( const char *input, FILE* dataout)
  1233. {
  1234.    FILE    *datain;
  1235.    char     buf[BUFSIZ];
  1236.    boolean  status = TRUE;
  1237.  
  1238. /*--------------------------------------------------------------------*/
  1239. /*                      Verify the input opened                       */
  1240. /*--------------------------------------------------------------------*/
  1241.  
  1242.    if (input == NULL)
  1243.       return FALSE;
  1244.    else
  1245.       datain = FOPEN(input, "r", TEXT);
  1246.  
  1247.    if (datain == NULL) {
  1248.       printerr(input);
  1249.       printmsg(0,"Unable to open input file \"%s\"", input);
  1250.       return FALSE;
  1251.    } /* datain */
  1252.  
  1253. /*--------------------------------------------------------------------*/
  1254. /*                       Loop to copy the data                        */
  1255. /*--------------------------------------------------------------------*/
  1256.  
  1257.    while (fgets(buf, BUFSIZ, datain) != 0)
  1258.    {
  1259.       if (fputs(buf, dataout) == EOF)     /* I/O error?               */
  1260.       {
  1261.          printmsg(0,"AppendData: I/O error on output file");
  1262.          printerr("dataout");
  1263.          fclose(datain);
  1264.          return FALSE;
  1265.       } /* if */
  1266.    } /* while */
  1267.  
  1268. /*--------------------------------------------------------------------*/
  1269. /*                      Close up shop and return                      */
  1270. /*--------------------------------------------------------------------*/
  1271.  
  1272.    if (ferror(datain))        /* Clean end of file on input?          */
  1273.    {
  1274.       printerr(input);
  1275.       clearerr(datain);
  1276.       status = FALSE;
  1277.    }
  1278.  
  1279.    fclose(datain);
  1280.    return status;
  1281.  
  1282. } /* AppendData */
  1283.  
  1284. /*--------------------------------------------------------------------*/
  1285. /*    M a i l S t a t u s                                             */
  1286. /*                                                                    */
  1287. /*    Send text in a mailbag file to address(es) specified by line.   */
  1288. /*--------------------------------------------------------------------*/
  1289.  
  1290. static boolean MailStatus(char *tempfile,
  1291.                           char *address,
  1292.                           char *subject)
  1293. {
  1294.    boolean status;
  1295.    char **envp;
  1296.  
  1297. /*--------------------------------------------------------------------*/
  1298. /*                            Invoke RMAIL                            */
  1299. /*--------------------------------------------------------------------*/
  1300.  
  1301.    envp = create_environment( "uucp", NULL );
  1302.  
  1303.    if ( subject == NULL )
  1304.       status = spawnlp( P_WAIT, E_rmail, E_rmail,
  1305.                         "-f", tempfile, "-w", address, NULL);
  1306.    else
  1307.       status = spawnlp( P_WAIT, E_rmail, E_rmail,
  1308.                         "-f", tempfile, "-w", "-s", subject, address, NULL);
  1309.  
  1310.    delete_environment( envp );
  1311.  
  1312. /*--------------------------------------------------------------------*/
  1313. /*                       Report errors, if any                        */
  1314. /*--------------------------------------------------------------------*/
  1315.  
  1316.    if ( status < 0 )
  1317.    {
  1318.       perror( E_rmail );
  1319.       printmsg(0,"Unable to execute rmail; status not delivered.");
  1320.    }
  1321.    else if ( status > 0 )
  1322.       printmsg(0, "Rmail returned error;\
  1323.  status delivery may be incomplete.");
  1324.  
  1325. /*--------------------------------------------------------------------*/
  1326. /*                          Return to caller                          */
  1327. /*--------------------------------------------------------------------*/
  1328.  
  1329.    return (status == 0 );
  1330.  
  1331. } /*MailStatus*/
  1332.